extends ICharacterComponent


class_name CharacterComponent
"""
角色组件,用于组织数据挂载其他子组件
"""


## 事件类型
enum Event {
    NONE = 0,
    ON_HIT_EXECUTE,
    ON_HIT_SOMETHING,
    ON_HIT_NOTHING,
    ON_HIT_OUT_OF_SCREEN,
}


## 所有挂载的行为
@export var effects: Array[EffectValue] = []


## 挂载的事件和处理器
var events: Dictionary[Event, EventProcessor] = {}


func __prepare() -> void:
    super.__prepare()

    for e in effects:
        take(e)

func get_character() -> CharacterComponent:
    return self

# 检测unique的效果是否和现有效果列表有冲突
func conflict(effect: EffectValue) -> Array:
    var conflict_effects: Array[EffectValue] = []
    for e_id in effect.support():
        if e_id == Event.NONE:
            break
        var processor: EventProcessor = events.get(e_id)
        if processor and processor.unique and processor.unique.behavior != effect.behavior:
            conflict_effects.append(processor.unique)
    return conflict_effects

# 装载效果
func take(effect: EffectValue) -> void:
    var is_unique: bool = true
    for e_id in effect.behavior.support():
        # unique 和 multi 以 None 分隔
        if e_id == Event.NONE:
            is_unique = false
            continue
        var processor: EventProcessor = events.get_or_add(e_id, EventProcessor.new())
        if is_unique:
            if processor.unique and processor.unique.behavior == effect.behavior:
                processor.unique.value += effect.value
            else:
                processor.unique = effect
        else:
            var is_contains: = false
            for e in processor.effects:
                if e.behavior == effect.behavior:
                    is_contains = true
                    e.value += effect.value
                    break
            if not is_contains:
                processor.effects.append(effect.duplicate())

# 卸载效果
func drop(effect: EffectValue) -> void:
    var is_unique: bool = true
    for e_id in effect.behavior.support():
        # unique 和 multi 以 None 分隔
        if e_id == Event.NONE:
            is_unique = false
            continue
        var processor: EventProcessor = events.get(e_id)
        if processor == null:
            continue
        if is_unique:
            if processor.unique and processor.unique.behavior == effect.behavior:
                if processor.unique.value > effect.value:
                    processor.unique.value -= effect.value
                else:
                    processor.unique = null
        else:
            var remove_indexs: Array[int] = []
            for i in range(len(processor.effects)):
                var e: EffectValue = processor.effects[i]
                if e.behavior == effect.behavior:
                    if e.value > effect.value:
                        e.value -= effect.value
                    else:
                        remove_indexs.append(i)
                    break
            for i in remove_indexs:
                processor.effects.pop_at(i)

func drop_all() -> void:
    events.clear()
    effects.clear()

func on_event(e_id: Event, meta: Dictionary[String, Variant]) -> bool:
    var e: EventProcessor = events.get(e_id)
    if e:
        return e.do_event(self, meta)
    # is_canceled = false
    return false

## 处理武器射击动作执行时的事件,返回是否需要取消发射子弹
func on_hit_execute(source: ProjectileResource, node: Projectile) -> bool:
    for e in effects:
        node.effects.append(e.duplicate())
    return on_event(Event.ON_HIT_EXECUTE, {"source": source, "projectile": node})

## 处理武器命中事件,返回是否取消销毁子弹
func on_hit_somthing(node: Projectile, body: Node2D, body_rid: RID, hit_normal: Vector2) -> bool:
    return on_event(Event.ON_HIT_SOMETHING,
    {
        "body": body,
        "body_rid": body_rid,
        "normal": hit_normal,
        "projectile": node
    })

## 处理武器未命中事件,返回是否取消销毁子弹
func on_hit_nothing(node: Projectile) -> bool:
    return on_event(Event.ON_HIT_NOTHING,
    {
        "projectile": node
    })

## 处理超出屏幕可视范围,返回是否销毁子弹
func on_hit_out_of_screen(node: Projectile, hit_direction: Vector2) -> bool:
    return on_event(Event.ON_HIT_OUT_OF_SCREEN,
    {
        "projectile": node,
        "direction": hit_direction
    })
